# -*- coding: utf-8 -*-
#   数据表转换成列表字段形式
# @Time    ：2023/2/25  11:57
# @Author  ：徐良
# @File    ：tableToList.py

from typing import Dict, List, Any, Optional
from PySide6.QtCore import Qt
from dbService.db_service import get_model
from PySide6.QtSql import QSqlQueryModel
from baseClass.tools.strFunction import get_instance_type
from PySide6.QtSql import QSqlRecord


class FcToDict:
    """
    将分离的父表和子表数据模型转换为嵌套的列表字段结构。
    父表和子表通过 fid 和 FEntityId 字段建立对应关系。
    """

    def __init__(self, **kwargs):
        """
        初始化并加载数据模型。
        参数：
            fTableSql (str): 查询父表数据的 SQL 语句
            cTableSql (str): 查询子表数据的 SQL 语句，需包含占位符 {ids}
        """
        self.f_sql: str = kwargs.get('fTableSql', '')
        self.c_sql: str = kwargs.get('cTableSql', '')

        self.parent_model: QSqlQueryModel = None
        self.child_model: QSqlQueryModel = None

        self.parent_fields: List[str] = []
        self.child_fields: List[str] = []

        self.parent_data: List[Dict[str, Any]] = []
        self.children_data: List[List[Dict[str, Any]]] = []

        self.__load_models()
        self.__extract_field_names()

    def __load_models(self):
        """
        加载父表和子表模型。子表 SQL 中的 {ids} 通过父表的 fid 替换。
        """
        self.parent_model = get_model(self.f_sql)

        # 提取父表所有 fid，用于子表查询
        fid_list = [
            str(self.parent_model.record(i).value('fid'))
            for i in range(self.parent_model.rowCount())
        ]
        ids_str = ','.join(fid_list)

        # 替换子表 SQL 中的 {ids} 占位符
        formatted_c_sql = self.c_sql.format(ids=ids_str)
        self.child_model = get_model(formatted_c_sql)

    def __extract_field_names(self):
        """
        提取父表和子表模型中的字段名，统一转为小写。
        """
        self.parent_fields = [
            str(self.parent_model.headerData(i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)).lower()
            for i in range(self.parent_model.columnCount())
        ]
        self.child_fields = [
            str(self.child_model.headerData(i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)).lower()
            for i in range(self.child_model.columnCount())
        ]

    def get_list_dict(self) -> Dict[str, List[Any]]:
        """
        将父子表数据转换为嵌套列表字典结构。
        返回：
            dict:
                {
                    'list': [父表记录字典...],
                    'childList': [[子表记录字典...], ...]
                }
        """

        def extract_parent_record(row_index: int) -> Dict[str, Any]:
            """提取指定行的父表记录为字典"""
            record = self.parent_model.record(row_index)
            return {field: record.value(field) for field in self.parent_fields}

        def extract_children_for(child_fid: Any) -> List[Dict[str, Any]]:
            """根据父记录的 fid，提取匹配的子记录列表"""
            children = []
            for row in range(self.child_model.rowCount()):
                record = self.child_model.record(row)
                if child_fid == record.value('fentityid'):
                    child_data = {field: record.value(field) for field in self.child_fields}
                    children.append(child_data)
            return children

        # 清空旧数据
        self.parent_data.clear()
        self.children_data.clear()

        # 遍历每一条父记录并提取子记录
        for i in range(self.parent_model.rowCount()):
            parent_record = extract_parent_record(i)
            self.parent_data.append(parent_record)

            fid = parent_record.get('fid')
            child_records = extract_children_for(fid)
            self.children_data.append(child_records)

        return {
            'list': self.parent_data,
            'childList': self.children_data
        }


class TableToListForPC:
    """
    将包含父子层级关系的同一个表格数据（来自 SQL 查询）转换为嵌套的父子结构列表。

    要求：
    - 通过字段 flevel 区分层级（1 表示父项，2 表示子项）
    - 通过 fid 和 fparentid 建立父子关系
    """

    def __init__(self, sql: str):
        """
        构造函数，加载模型并提取字段名。
        :param sql: 查询语句，用于获取数据模型。
        """
        self.sql = sql
        self.__model = None  # 查询模型
        self.__fields_list: List[str] = []  # 所有字段名列表
        self.__parent_list: List[Dict[str, Any]] = []  # 父项记录列表
        self.__child_list_group: List[List[Dict[str, Any]]] = []  # 每个父项对应的子项列表

        self.__load_model()
        self.__extract_field_names()

    def __load_model(self) -> None:
        """执行 SQL 查询并生成数据模型。"""
        self.__model = get_model(self.sql)

    def __extract_field_names(self) -> None:
        """提取表头字段名，转为小写存入字段列表中。"""
        self.__fields_list.clear()
        column_count = self.__model.columnCount()
        for i in range(column_count):
            field_name = str(self.__model.headerData(
                i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)).lower()
            self.__fields_list.append(field_name)

    def __build_parent_record(self, record: QSqlRecord) -> Dict[str, Any]:
        """
        将父项记录封装为字段字典。
        :param record: 父项记录。
        :return: 该记录对应的字段值字典。
        """
        return {field: record.value(field) for field in self.__fields_list}

    def __find_child_records(self, parent_fid: Any) -> List[Dict[str, Any]]:
        """
        查找指定父项的所有子记录。
        :param parent_fid: 父项的 fid 值。
        :return: 所有对应子项的字段值字典列表。
        """
        child_records: List[Dict[str, Any]] = []
        for row in range(self.__model.rowCount()):
            record = self.__model.record(row)
            if (record.value("FParentId") == parent_fid and
                    record.value("FLevel") == 3):
                child_data = {field: record.value(field) for field in self.__fields_list}
                child_records.append(child_data)
        return child_records

    def get_list_dict(self) -> Dict[str, List[Any]]:
        """
        获取最终结果：父项列表 + 对应的子项嵌套列表。
        :return: {'list': 父项记录列表, 'childList': 每个父项对应的子记录列表}
        """
        self.__parent_list.clear()
        self.__child_list_group.clear()

        for row in range(self.__model.rowCount()):
            record = self.__model.record(row)
            if record.value("FLevel") == 2:
                # 构建父项记录
                parent_data = self.__build_parent_record(record)
                self.__parent_list.append(parent_data)

                # 查找对应的子项
                parent_fid = record.value("fid")
                children = self.__find_child_records(parent_fid)
                self.__child_list_group.append(children)

        return {
            "list": self.__parent_list,
            "childList": self.__child_list_group
        }


class TableToListDict:
    """
    将 SQL 查询结果（QSqlQueryModel）转换为列表形式的字典集合。
    每一条记录为一个字典对象，包含字段名及其值。
    """

    def __init__(self, sql: str):
        """
        初始化转换器，加载模型和字段信息。
        :param sql: 用于查询的 SQL 语句。
        """
        self.sql = sql
        self.__model = None
        self.__fields_list: List[str] = []
        self.__list: List[Dict[str, Any]] = []

        self.__load_model()
        self.__extract_field_names()

    def __load_model(self) -> None:
        """加载查询模型。"""
        self.__model = get_model(self.sql)

    def __extract_field_names(self) -> None:
        """提取字段名列表（统一转为小写）。"""
        self.__fields_list.clear()
        for i in range(self.__model.columnCount()):
            field = str(self.__model.headerData(
                i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)).lower()
            self.__fields_list.append(field)

    def __record_to_dict(self, record: QSqlRecord) -> Dict[str, Any]:
        """
        将一条记录转换为字典，自动格式化日期/时间字段。
        :param record: QSqlRecord 对象。
        :return: 字段字典。
        """
        data: Dict[str, Any] = {}
        for field in self.__fields_list:
            val = record.value(field)
            val_type = get_instance_type(val)
            if val_type == 'QDate':
                data[field] = val.toString("yyyy-MM-dd")
            elif val_type == 'QDateTime':
                data[field] = val.toString("yyyy-MM-dd hh:mm:ss")
            else:
                data[field] = val
        return data

    def get_list_dict(self, sql: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        获取转换后的列表字典结构。
        可传入新的 SQL 语句以重新加载模型。
        :param sql: 可选的 SQL 语句。
        :return: 记录字典列表。
        """
        if sql:
            self.sql = sql
            self.__load_model()
            self.__extract_field_names()

        self.__list.clear()
        for row in range(self.__model.rowCount()):
            record = self.__model.record(row)
            self.__list.append(self.__record_to_dict(record))

        return self.__list


class ModelToList:
    """
    用于将模型（QSqlQueryModel）中的记录转换为字典列表格式。
    可支持字段筛选，常用于父子表不在同一张表时，仅提取父表记录。
    """

    def __init__(self, model: QSqlQueryModel, field_list: Optional[List[str]] = None):
        """
        初始化转换器。
        :param model: 查询得到的 QSqlQueryModel 对象。
        :param field_list: 可选的字段名列表，若为 None 则自动提取所有字段。
        """
        self.__model = model
        self.__list: List[Dict[str, Any]] = []

        # 提取字段列表（全部字段或自定义字段）
        if field_list is not None:
            self.__fields_list = field_list
        else:
            self.__fields_list: List[str] = []
            self.__extract_field_names()

    def __extract_field_names(self) -> None:
        """从模型中提取所有字段名，统一转小写。"""
        self.__fields_list.clear()
        for i in range(self.__model.columnCount()):
            field = str(self.__model.headerData(
                i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)).lower()
            self.__fields_list.append(field)

    def __record_to_dict(self, record: QSqlRecord) -> Dict[str, Any]:
        """
        将一条 QSqlRecord 转换为字典。
        :param record: QSqlRecord 记录。
        :return: 字段名到字段值的字典。
        """
        return {field: record.value(field) for field in self.__fields_list}

    def get_list_dict(self) -> List[Dict[str, Any]]:
        """
        获取模型中所有记录组成的字典列表。
        :return: 所有记录字典的列表。
        """
        self.__list.clear()
        for i in range(self.__model.rowCount()):
            record = self.__model.record(i)
            self.__list.append(self.__record_to_dict(record))
        return self.__list

    def get_list_dict_by_sel(self) -> List[Dict[str, Any]]:
        """
        获取 FSel=1 的记录组成的字典列表，用于筛选被勾选的记录等。
        :return: 符合条件的记录字典列表。
        """
        self.__list.clear()
        for i in range(self.__model.rowCount()):
            record = self.__model.record(i)
            # 判断 FSel 字段为 1
            if record.value("FSel") == 1:
                self.__list.append(self.__record_to_dict(record))
        return self.__list


class ListFromModel:
    """
    从 QSqlQueryModel 获取字段列表（列名）及值列表（二维列表）
    """

    def __init__(self, model: QSqlQueryModel):
        """
        初始化
        :param model: 数据模型，QSqlQueryModel 或兼容接口
        """
        self._model = model

    def get_field_list(self) -> List[str]:
        """
        获取模型的字段名列表，全部转换为小写
        :return: List[str] 字段名列表
        """
        field_list = []
        column_count = self._model.columnCount()
        for i in range(column_count):
            header = self._model.headerData(i, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)
            field_list.append(str(header).lower())
        return field_list

    def get_value_list(self) -> List[List[Any]]:
        """
        获取所有数据行的值组成的二维列表
        :return: List[List[Any]] 每行为一个记录的字段值列表
        """
        field_list = self.get_field_list()
        row_count = self._model.rowCount()
        value_list = []

        for row_index in range(row_count):
            row_data = self._extract_row_values(row_index, field_list)
            value_list.append(row_data)

        return value_list

    def _extract_row_values(self, row_index: int, field_list: List[str]) -> List[Any]:
        """
        提取指定行的所有字段值，统一格式化处理
        :param row_index: 行索引
        :param field_list: 字段名列表
        :return: List[Any] 当前行的值列表
        """

        def format_value(val: Any) -> Any:
            """格式化处理字段值（日期等类型转换为字符串）"""
            type_str = get_instance_type(val)
            if type_str == 'QDate':
                return val.toString("yyyy-MM-dd")
            elif type_str == 'QDateTime':
                return val.toString("yyyy-MM-dd hh:mm:ss")
            return val

        values = []
        record = self._model.record(row_index)
        for field in field_list:
            raw_value = record.value(field)
            values.append(format_value(raw_value))

        return values

